<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="styles.css">
  <title>本机deepseek调用测试</title>
  <style type="text/css">
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: Arial, sans-serif;
      background-color: #f0f0f0;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      padding: 0;
    }

    .chat-container {
      width: 60vw;
      height: 80vh;
      background-color: white;
      border-radius: 10px;
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
      overflow: hidden;
      position: relative;
    }

    .chat-header {
      height: 50px;
      line-height: 50px;
      padding: 0 15px;
      background-color: #f0f0f0;
      border-bottom: 1px solid #ccc;
      font-size: 16px;
    }

    .chat-content {
      height: calc(100% - 50px - 50px);
      overflow-y: scroll;
      padding: 10px;
    }

    .chat-message {
      margin-bottom: 10px;
      display: flex;
      align-items: start;
    }

    .avatar {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      margin-right: 10px;
      flex-shrink: 0;
    }

    .message-text {
      background-color: #f0f0f0;
      padding: 10px;
      border-radius: 10px;
    }

    .self-message {
      justify-content: flex-end;
    }

    .self-message.message-text {
      background-color: #dcf8c6;
    }

    .time-message {
      text-align: center;
      color: #999;
      font-size: 12px;
    }

    .chat-footer {
      height: 50px;
      display: flex;
      align-items: center;
      padding: 0 10px;
      background-color: #f0f0f0;
    }

    .emoji-button,
    .file-button,
    .scissors-button {
      background-color: transparent;
      border: none;
      font-size: 20px;
      margin-right: 10px;
    }

    .input-message {
      flex: 1;
      height: 30px;
      border: none;
      border-radius: 5px;
      padding: 0 10px;
    }

    .send-button {
      background-color: #dcf8c6;
      border: none;
      height: 30px;
      padding: 0 15px;
      border-radius: 5px;
      margin-left: 10px;
    }

    .self-message-text {
      background-color: #dcf8c6;
    }

    .cancel-typing-button {
      background-color: #ff6666;
      color: white;
      border: none;
      padding: 5px 10px;
      border-radius: 5px;
      cursor: pointer;
      margin-top: 5px;
      margin-left: 50px;
    }
  </style>
</head>

<body>
  <div class="chat-container" id="chw">
    <div class="chat-header">
      <span class="user-name"> deepSeek人工智障 </span>
    </div>
    <div class="chat-content" id="chatContent">
      <div class="chat-message">
        <img src="../images/deepseek.jpg" alt="头像" class="avatar">
        <div class="message-text">欢迎使用deepseek人工智能程序哇！</div>
      </div>
    </div>
    <div class="chat-footer">
      <button class="emoji-button">&#128514;</button>
      <button class="file-button">&#9993;</button>
      <button class="scissors-button">&#9989;</button>
      <input :disabled='isLoding' type="text" @keyup.enter="sendMessage" placeholder="输入消息" class="input-message" v-model="inputText">
      <button class="send-button" @click="sendMessage">发送(S)</button>
    </div>
  </div>
</body>

<script src="../js/jquery-3.6.0.js"></script>
<script src="../js/vue.js"></script>
<script>
  let app1 = new Vue({
    el: '#chw',
    data: {
      // 输入要问的问题
      inputText: '',
      // 是否处于加载状态
      isLoding: false,
      // 标记请求是否已取消
      isCancelled: false,
      // 用于存储逐字拼接的回复内容
      currentReply: '',
      // 完整的回复内容
      fullReply: '',
      // 记录当前处理到的字符位置
      charIndex: 0,
      // 存储当前回复消息的 DOM 元素
      currentReplyElement: null,
      // 存储取消按钮的 DOM 元素
      cancelButton: null
    },
    methods: {
      sendMessage() {
        if (this.inputText && this.inputText.length > 0) {
          const message = `
            <div class="chat-message self-message">
              <img src="../images/me.jpg" alt="头像" class="avatar">
              <div class="message-text self-message-text">${this.inputText}</div>
            </div>
          `;
          $('#chatContent').append(message);

          // 获取聊天内容区域的 DOM 元素
          const chatContent = document.getElementById('chatContent');
          // 将滚动条位置设置为内容的高度，实现滚动到最底部
          chatContent.scrollTop = chatContent.scrollHeight;

          this.isLoding = true;
          this.isCancelled = false;
          this.currentReply = '';
          this.fullReply = '';
          this.charIndex = 0;
          this.currentReplyElement = null;
          this.cancelButton = null;
          const vm = this;

          // 创建一个 AbortController 用于取消请求
          const controller = new AbortController();
          const signal = controller.signal;

          // 发送请求 访问 deepseek 的 api
          let params = {
            model: 'deepseek-r1:8b',
            prompt: this.inputText
          };
          $.ajax({
            url: 'http://localhost:11434/api/generate',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(params),
            signal: signal,
            success: function (data) {
              if (!vm.isCancelled) {
                // 将响应数据按行分割成数组
                const lines = data.split('\n');
                let fullResponse = '';

                // 遍历每一行数据
                for (const line of lines) {
                  if (line.trim() === '') continue;
                  const data = JSON.parse(line);
                  fullResponse += data.response;
                  if (data.done) {
                    break;
                  }
                }
                fullResponse = fullResponse.replaceAll("<think>", "")
                fullResponse = fullResponse.replaceAll("</think>", "");

                vm.fullReply = fullResponse;
                vm.startTyping();
              }
            },
            error: function (error) {
              vm.isLoding = false;
            }
          });
          this.inputText = '';
        }
      },
      startTyping() {
        const answer = `
          <div class="chat-message">
            <img src="../images/deepseek.jpg" class="avatar" alt="头像">
            <div class="message-text">${this.currentReply}</div>
            <button class="cancel-typing-button">取消</button>
          </div>
        `;
        const $answer = $(answer);
        $('#chatContent').append($answer);
        this.currentReplyElement = $answer.find('.message-text');
        this.cancelButton = $answer.find('.cancel-typing-button');
        this.cancelButton.on('click', this.cancelTyping);

        this.typeReply();
      },
      typeReply() {
        if (this.isCancelled || this.charIndex >= this.fullReply.length) {
          this.isLoding = false;
          if (this.cancelButton) {
            this.cancelButton.hide();
          }
          return;
        }
        // 逐字添加到当前回复中
        this.currentReply += this.fullReply.charAt(this.charIndex);
        this.charIndex++;

        // 更新页面上的回复内容
        this.currentReplyElement.text(this.currentReply);

        // 将滚动条位置设置为内容的高度，确保滚动到最底部
        const chatContent = document.getElementById('chatContent');
        chatContent.scrollTop = chatContent.scrollHeight;

        setTimeout(() => {
          this.typeReply();
        }, 50); // 调整打字速度，单位为毫秒
      },
      cancelTyping() {
        this.isCancelled = true;
        this.isLoding = false;
        if (this.cancelButton) {
          this.cancelButton.hide();
        }
      }
    },
    mounted: function () {
      console.log("欢迎使用霸天的 deepseek~~~")
    }
  })
</script>

</html>